#pragma once
#include "Block.h"

namespace AppliedCryptography
{
	namespace AC = AppliedCryptography;

	template<unsigned int TBlockSize>
	class BlockData
	{
	private:
		std::vector<byte> _content;

	public:
		BlockData()
		{ /*...*/ };

		BlockData(const std::vector<byte> data) : _content(data)
		{ /*...*/ };

		BlockData(const AC::Block<TBlockSize> data) : _content(data.Get())
		{ /*...*/ };

	private:
		unsigned int BlockLength(unsigned int blockIndex) const
		{
			if(blockIndex >= this->Blocks())
				throw AC::Exception("Index too large!");

			if((blockIndex+1) == this->Blocks())
				return this->LastBlockLength();

			return TBlockSize;
		};

	public:
		virtual std::vector<byte> Get() const
		{
			return _content;
		};


		virtual unsigned int Blocks() const
		{
			unsigned int blocks = (_content.size() / TBlockSize);

			if(_content.size() % TBlockSize > 0)
				++blocks;

			return blocks;
		};

		virtual unsigned int Size() const
		{
			return _content.size();
		};

		virtual unsigned int LastBlockLength() const
		{
			unsigned int remainder = _content.size() % TBlockSize;

			return (remainder != 0) ? remainder : TBlockSize;
		};

		virtual const AC::Block<TBlockSize> At(unsigned int blockIndex) const
		{
			AC::Block<TBlockSize> block;

			if(blockIndex >= this->Blocks())
				throw AC::Exception("Index too large!");

			for(unsigned int i=0; i < this->BlockLength(blockIndex); ++i)
				block[i] = _content[blockIndex * TBlockSize + i];

			return block;
		};

		virtual const AC::Block<TBlockSize> operator[] (unsigned int index) const
		{
			return this->At(index);
		};

		virtual AC::Block<TBlockSize> At(unsigned int blockIndex)
		{
			AC::Block<TBlockSize> block;

			if(blockIndex >= this->Blocks())
				throw AC::Exception("Index too large!");

			for(unsigned int i=0; i < this->BlockLength(blockIndex); ++i)
				block[i] = _content[blockIndex * TBlockSize + i];

			return block;
		};

		virtual AC::Block<TBlockSize> operator[] (unsigned int index)
		{
			return this->At(index);
		};

		virtual void Delete(unsigned int blockIndex)
		{
			//blockIndex * TBlockSize
			//blockIndex * TBlockSize + BlockLength(blockIndex) - 1
			std::vector<byte>::iterator itBegin;
			std::vector<byte>::iterator itEnd;
			std::vector<byte>::iterator result;

			itBegin = _content.begin() + blockIndex * TBlockSize;
			itEnd =  _content.begin() + blockIndex * TBlockSize + BlockLength(blockIndex);
			result = _content.erase(itBegin, itEnd);
		};

		virtual void Add(AC::Block<TBlockSize> block, unsigned int len)
		{
			for(unsigned int i=0; i < len; ++i)
				_content.push_back(block[i]);
		};
	};
};
